package main

import "fmt"

// 接口是一种协议 - 程序员 - 只要你能够 1.写代码 2，解决bug 其实就是一组方法的集合
type Programmer interface {
	Coding() string //方法只是声明
	Debug() string
}

// 设计
type Design interface {
	Design() string
}

// 管理 实现 接口组合 需要会编程，还有会设计 同时还要能管理
type Manager interface {
	Programmer
	Design
	Manage() string
}

// java php 的话一个类型只有继承一个接口才行，如果你继承了这个接口的话 那么这个接口中的所有方法你必须全部实现

type Pythoner struct {
	UIdesign
}

type UIdesign struct {
}

func (d UIdesign) Design() string {
	fmt.Println("UIdesign")
	return "UIdesign"
}

type Goer struct {
}

func (p Pythoner) Coding() string {
	fmt.Println("python 开发者")
	return "python 开发者"
}

func (p Pythoner) Debug() string {
	fmt.Println("python debug")
	return "python debug"
}
func (p Pythoner) Manage() string {
	fmt.Println("python Manage")
	return "python Manage"
}

func (p Goer) Coding() string {
	fmt.Println("go 开发者")
	return "go 开发者"
}

func (p Goer) Debug() string {
	fmt.Println("go debug")
	return "go debug"
}

// 对于pythoner这个结构体来说，你实现任何方法都可以，但你只要不全部实现 Coding Dubug的话，那你就不是一个Programmer类型
// 1. Pythoner 本身自己就是一个类型，那我何必在意是不是programmer
// 2. 面向对象：封装 继承 多态 多态的概念对于很多pythoner会很陌生，对于静态语言来说多态很重要
// 3. 在讲解多态之前，我们来对interface做一个说明，在go语言中inerface是一个类型，可以基于类型声明一个变量，是一种抽象类型

// var pro Programmer

// 举例说明多态，开发电商网站实现各种支付接口：微信，支付宝，银行卡 每一种支付都有统一的接口
// 定一个协议1 创建订单 2 支付 3 查询订单状态 4 退款
// 支付发起后
// type Alipay struct {
// }
// type Wechat struct {
// }
// type Bank struct {
// }

// 发起支付后声明哪个接口呢？
// 可以定义一个通用类型
// type Tongyong interface{

// }
// 多态 申明的类型是一种兼容类型，但是实际赋值的时候以另外一种类型
// var x Tongyong
// x = Alipay{}
// x = Wechat{}
// x = Bank{}
// 后期使用时直接调用x的方法
// x.pay()

// 还有个例子必须缓存的实现 前期redis 后期需要切换的memcache类型，如何无缝切换

func Handle(p Programmer) { // 因为此处接收的是一个通用的类型 所以任何实现了 Programmer方法的类型都可以传递进来，而内部的代码都不需要调整
	// 程序员处理代码
}

// go 内置的error是一个抽象接口所以我们可以自定义一个error,实现里面的Error方法
type Myerror struct {
}

func (e Myerror) Error() string {
	return "错误"
}
func main() {
	// 因为pythoner实现了Programmer的coding和debug方法所以可以直接声明 Pythonner类型赋值给Programmer
	var pro Programmer = Pythoner{} //此处只要实现了都可以赋值，下面的代码都不需要修改，实现了多态
	pro.Coding()

	// 接口是一种类型，但是一种特殊的抽象类型 struc是具象的
	p := Pythoner{}
	fmt.Printf("%T\n", p)
	var py Programmer = Pythoner{} // 虽然py声明的类型是 Programmer 但实际打印的类型就是 赋值的类型Pythoner
	fmt.Printf("%T\n", py)
	var go1 Programmer = Goer{} // 虽然go1声明的类型是 Programmer 但实际打印的类型就是 赋值的类型Goer
	fmt.Printf("%T\n", go1)
	// 给抽象类型赋值必须给他一个具象的类型

	// 1. go struct组合一起实现了接口也是可以的
	// 2. 接口本身也可以组合

	var m Manager = Pythoner{} //struct 组合拼接 实现了所有的方法也是没有问题的
	m.Manage()
	// go语言也推荐使用鸭子类型 error
	var err error = Myerror{}
	fmt.Println(err.Error())
	s := "文件不存在"
	var err1 error = fmt.Errorf("%s", s)
	fmt.Println(err1)

}
